package model;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

import util.Message;
import util.MsgType;

public class Head implements Runnable {
	private State state;
	private LinkedBlockingQueue<Message> pipe;
	private Semaphore[] steps;
	private CyclicBarrier[] barriers;
	
	public Head() {
		
	}
	
	public Head(State state, LinkedBlockingQueue<Message> pipe, Semaphore[] steps, CyclicBarrier[] barriers)  {
		this.state = state;
		this.pipe = pipe;
		this.steps = steps;
		this.barriers = barriers;
	}
	
	
	@Override
	public void run() {
		try {
		for(int i = 0; i < state.numFeet(); i++){
			
				steps[i].acquire();

		}
		state.headReady.countDown();

		state.feetReady.await();
		
		System.out.println(state.getCoords());
		
		while(true) {
			int awaken_foot = state.turn();
			steps[awaken_foot].release();
			// blocks until foot will write a message into a pipe
			Message msg = pipe.take();
			
			if(msg.getType() == MsgType.exception) {
				throw msg.getEx();
			} else {
				if(msg.compare("fail")) {
					state.changeTurn();
				}
			}
			steps[awaken_foot].acquire();
			
			barriers[awaken_foot].await();
			barriers[awaken_foot].reset();
			System.out.println(state.getCoords());	
			TimeUnit.SECONDS.sleep(1);
		}
		
		
		} catch (InterruptedException e) {
			System.out.println("Interrupted exception occured. Program interrupted.");
		} catch (BrokenBarrierException e) {
			System.out.println("Broken Barrier exception occured. Program interrupted.");
		} catch (Exception e) {
			System.out.println("Exception from Foot thread. Program interrupted.");
		}
	}

}
